/********************************************************/
/*	Copyright (C) 2016 Gong Li Bin		 	*/
/*	Project:	GlbLib-1.0.0			*/
/*	Author:		gong_libin			*/
/*	Date:		2016_06_01			*/
/*	File:		GlbPro.cpp			*/
/********************************************************/

#include "GlbPro.h"

namespace GlbNet
{

CGlbPro::CGlbPro()
{
	m_puszBody = NULL;
	memset(m_uszExHead, '\0', GLB_PRO_EXPA);
	memset(&m_stHead, '\0', sizeof(GLBPROHEAD_S));
}

CGlbPro::~CGlbPro()
{
}

UCHAR CGlbPro::GlbProGetFlag()
{
	return m_stHead.m_ucFlag;
}

UCHAR CGlbPro::GlbProGetWide()
{
	return m_stHead.m_ucWide;
}

UCHAR CGlbPro::GlbProGetType()
{
	return m_stHead.m_ucType;
}

UCHAR CGlbPro::GlbProGetVerb()
{
	return m_stHead.m_ucVerb;
}

UCHAR CGlbPro::GlbProGetAttr()
{
	return m_stHead.m_ucAttr;
}

int CGlbPro::GlbProGetLength()
{
	return m_stHead.m_iLength;
}

USHORT CGlbPro::GlbProGetTotal()
{
	return m_stHead.m_usTotal;
}

UCHAR CGlbPro::GlbProGetExpand()
{
	return m_stHead.m_ucExpand;
}

UCHAR CGlbPro::GlbProGetResult()
{
	return m_stHead.m_ucResult;
}

UCHAR CGlbPro::GlbProGetVersion()
{
	return m_stHead.m_ucVersion;
}

UCHAR CGlbPro::GlbProGetProtocol()
{
	return m_stHead.m_ucProtocol;
}

UCHAR CGlbPro::GlbProGetResponse()
{
	return m_stHead.m_ucResponse;
}

UCHAR* CGlbPro::GlbProGetBody()
{
	return m_puszBody;
}

UCHAR* CGlbPro::GlbProGetExHead()
{
	return m_uszExHead;
}

GLBPROHEAD_S* CGlbPro::GlbProGetHead()
{
	return &m_stHead;
}

void CGlbPro::GlbProPutFlag(UCHAR ucFlag)
{
	m_stHead.m_ucFlag = ucFlag;

	return;
}

void CGlbPro::GlbProPutWide(UCHAR ucWide)
{
	m_stHead.m_ucWide = ucWide;

	return;
}

void CGlbPro::GlbProPutType(UCHAR ucType)
{
	m_stHead.m_ucType = ucType;

	return;
}

void CGlbPro::GlbProPutVerb(UCHAR ucVerb)
{
	m_stHead.m_ucVerb = ucVerb;

	return;
}

void CGlbPro::GlbProPutAttr(UCHAR ucAttr)
{
	m_stHead.m_ucAttr = ucAttr;

	return;
}

void CGlbPro::GlbProPutLength(int iLength)
{
	m_stHead.m_iLength = iLength;

	return;
}

void CGlbPro::GlbProPutTotal(USHORT usTotal)
{
	m_stHead.m_usTotal = usTotal;

	return;
}

void CGlbPro::GlbProPutExpand(UCHAR ucExpand)
{
	m_stHead.m_ucExpand = ucExpand;

	return;
}

void CGlbPro::GlbProPutResult(UCHAR ucResult)
{
	m_stHead.m_ucResult = ucResult;

	return;
}

void CGlbPro::GlbProPutVersion(UCHAR ucVersion)
{
	m_stHead.m_ucVersion = ucVersion;

	return;
}

void CGlbPro::GlbProPutProtocol(UCHAR ucProtocol)
{
	m_stHead.m_ucProtocol = ucProtocol;

	return;
}

void CGlbPro::GlbProPutResponse(UCHAR ucResponse)
{
	m_stHead.m_ucResponse = ucResponse;

	return;
}

void CGlbPro::GlbProPutBody(UCHAR* puszBody)
{
	m_puszBody = puszBody;

	return;
}

void CGlbPro::GlbProPutExHead(UCHAR* puszExHead)
{
	memcpy(m_uszExHead, puszExHead, GLB_PRO_EXPA);

	return;
}

void CGlbPro::GlbProPutHead(GLBPROHEAD_S* pstHead)
{
	memcpy(&m_stHead, pstHead, sizeof(GLBPROHEAD_S));

	return;
}

void CGlbPro::GlbProReset()
{
	memset(&m_stHead, '\0', sizeof(GLBPROHEAD_S));
	m_puszBody = NULL;

	return;
}

void CGlbPro::GlbProDisplay()
{
	GLB_PRINT("Flag: 0x%02x\t", m_stHead.m_ucFlag);
	GLB_PRINT("Version: 0x%02x\t", m_stHead.m_ucVersion);
	GLB_PRINT("Protocol: 0x%02x\t", m_stHead.m_ucProtocol);
	GLB_PRINT("Wide: 0x%02x\t", m_stHead.m_ucWide);
	GLB_PRINT("Response: 0x%02x\t", m_stHead.m_ucResponse);
	GLB_PRINT("Expand: 0x%02x\n", m_stHead.m_ucExpand);
	GLB_PRINT("Type: 0x%02x\t", m_stHead.m_ucType);
	GLB_PRINT("Verb: 0x%02x\t", m_stHead.m_ucVerb);
	GLB_PRINT("Attr: 0x%02x\t", m_stHead.m_ucAttr);
	GLB_PRINT("Result: 0x%02x\t", m_stHead.m_ucResult);
	GLB_PRINT("Total: %d\t", m_stHead.m_usTotal);
	GLB_PRINT("Length: %d\t", m_stHead.m_iLength);

	if (GLB_PRO_1 == m_stHead.m_ucExpand) {
		GLB_PRINT("ExHead: %p\t", m_uszExHead);
	}
	else {
		GLB_PRINT("ExHead: NULL\t");
	}

	if (NULL != m_puszBody) {
		GLB_PRINT("Body: %p\n", m_puszBody);
	}
	else {
		GLB_PRINT("Body: NULL\n");
	}

	return;
}

void CGlbPro::GlbProClone(CGlbPro& rCPro)
{
	memcpy(&m_stHead, rCPro.GlbProGetHead(), sizeof(GLBPROHEAD_S));
	memcpy(&m_uszExHead, rCPro.GlbProGetExHead(), GLB_PRO_EXPA);
	m_puszBody = rCPro.GlbProGetBody();

	return;
}

void CGlbPro::GlbProInduce(GLBPROHEAD_S* pstHead)
{
	memcpy(&m_stHead, pstHead, sizeof(GLBPROHEAD_S));

	return;
}

void CGlbPro::GlbProParse(UCHAR* puszPacket, int iLength)
{
	UCHAR* puszCur = puszPacket;

	m_stHead.m_ucFlag = *puszCur;
	puszCur += sizeof(UCHAR);

	m_stHead.m_ucVersion = *puszCur >> 4;
	m_stHead.m_ucProtocol = (*puszCur & 0x0f) >> 3;
	m_stHead.m_ucWide = (*puszCur & 0x07) >> 2;
	m_stHead.m_ucResponse = (*puszCur & 0x03) >> 1;
	m_stHead.m_ucExpand = *puszCur & 0x01;
	puszCur += sizeof(UCHAR);

	m_stHead.m_ucType = *puszCur;
	puszCur += sizeof(UCHAR);

	m_stHead.m_ucVerb = *puszCur;
	puszCur += sizeof(UCHAR);

	m_stHead.m_ucAttr = *puszCur;
	puszCur += sizeof(UCHAR);

	m_stHead.m_ucResult = *puszCur;
	puszCur += sizeof(UCHAR);

	m_stHead.m_usTotal = ntohs(*(USHORT*)puszCur);
	puszCur += sizeof(USHORT);

	m_stHead.m_iLength = ntohl(*(int*)puszCur);
	puszCur += sizeof(int);

	if (GLB_PRO_1 == m_stHead.m_ucExpand) {
		memcpy(m_uszExHead, puszCur, GLB_PRO_EXPA);
		puszCur += GLB_PRO_EXPA;
		if (iLength > GLB_PRO_HEAD + GLB_PRO_EXPA) {
			m_puszBody = puszCur;
		}
	}
	else {
		if (iLength > GLB_PRO_HEAD) {
			m_puszBody = puszCur;
		}
	}

	return;
}

void CGlbPro::GlbProCreate(UCHAR* puszPacket, int iLength)
{
	UCHAR* puszCur = puszPacket;

	*puszCur = m_stHead.m_ucFlag;
	puszCur += sizeof(UCHAR);

	*puszCur = m_stHead.m_ucVersion << 4;
	*puszCur |= m_stHead.m_ucProtocol << 3;
	*puszCur |= m_stHead.m_ucWide << 2;
	*puszCur |= m_stHead.m_ucResponse << 1;
	*puszCur |= m_stHead.m_ucExpand;
	puszCur += sizeof(UCHAR);

	*puszCur = m_stHead.m_ucType;
	puszCur += sizeof(UCHAR);

	*puszCur = m_stHead.m_ucVerb;
	puszCur += sizeof(UCHAR);

	*puszCur = m_stHead.m_ucAttr;
	puszCur += sizeof(UCHAR);

	*puszCur = m_stHead.m_ucResult;
	puszCur += sizeof(UCHAR);

	*(USHORT*)puszCur = htons(m_stHead.m_usTotal);
	puszCur += sizeof(USHORT);

	*(int*)puszCur = htonl(m_stHead.m_iLength);
	puszCur += sizeof(int);

	if (GLB_PRO_1 == m_stHead.m_ucExpand) {
		memcpy(puszCur, m_uszExHead, GLB_PRO_EXPA);
		if (NULL != m_puszBody) {
			memcpy(puszCur + GLB_PRO_EXPA, m_puszBody, m_stHead.m_iLength < iLength ? m_stHead.m_iLength : iLength);
		}
	}
	else {
		if (NULL != m_puszBody) {
			memcpy(puszCur, m_puszBody, m_stHead.m_iLength < iLength ? m_stHead.m_iLength : iLength);
		}
	}

	return;
}

void CGlbPro::GlbProRequest(UCHAR* puszPacket)
{
	GLBPROHEAD_S stHead = {
		GLB_PRO_FLAG,
		GLB_PRO_0,
		GLB_PRO_GLBRL,
		GLB_PRO_0,
		GLB_PRO_Y,
		GLB_PRO_0,
		GLB_PRO_0,
		GLB_PRO_0,
		GLB_PRO_0,
		GLB_PRO_0,
		GLB_PRO_0,
		GLB_PRO_0,
	};

	GlbProInduce(&stHead);
	GlbProCreate(puszPacket, GLB_PRO_HEAD);

	return;
}

void CGlbPro::GlbProResponse(UCHAR* puszPacket)
{
	GLBPROHEAD_S stHead = {
		GLB_PRO_FLAG,
		GLB_PRO_0,
		GLB_PRO_GLBRL,
		GLB_PRO_0,
		GLB_PRO_N,
		GLB_PRO_0,
		GLB_PRO_0,
		GLB_PRO_0,
		GLB_PRO_0,
		GLB_DEF_SUCC,
		GLB_PRO_0,
		GLB_PRO_0,
	};

	GlbProInduce(&stHead);
	GlbProCreate(puszPacket, GLB_PRO_HEAD);

	return;
}

void GlbProKvFree(GLBPROKV_S** ppstKv, USHORT usTotal)
{
	USHORT usCount = 0;

	for (usCount = 0; usCount < usTotal; usCount ++) {
		if (NULL != (*ppstKv + usCount)->m_puszValue) {
			GlbFree((void**)&(*ppstKv + usCount)->m_puszValue);
		}
	}
	GlbFree((void**)ppstKv);

	return;
}

void GlbProKvDisplay(GLBPROKV_S* pstKv, USHORT usTotal)
{
	USHORT usCount = 0;
	char* pszValue = NULL;

	while (usCount < usTotal) {
		if ('\0' != (pstKv + usCount)->m_ucKey) {
			if (NULL != (pszValue = (char*)GlbMalloc(sizeof(char) * (pstKv + usCount)->m_iLength + 1))) {
				memcpy(pszValue, (pstKv + usCount)->m_puszValue, (pstKv + usCount)->m_iLength);
				GLB_PRINT("Key[%03d] -> Len[%08d] -> Val[%s]\n", (pstKv + usCount)->m_ucKey, (pstKv + usCount)->m_iLength, pszValue);
				GlbFree((void**)&pszValue);
			}
		}
		else {
			break;
		}
		usCount += 1;
	}

	return;
}

GLBPROKV_S* GlbProKvMalloc(USHORT usTotal, int iSize)
{
	USHORT usCount = 0;
	GLBPROKV_S* pstKv = NULL;

	if (NULL != (pstKv = (GLBPROKV_S*)GlbMalloc(sizeof(GLBPROKV_S) * usTotal))) {
		for (usCount = 0; usCount < usTotal; usCount ++) {
			if (NULL == ((pstKv + usCount)->m_puszValue = (UCHAR*)GlbMalloc(sizeof(UCHAR) * iSize))) {
				GLB_ERROR("%s\n", strerror(errno));
				GlbProKvFree(&pstKv, usTotal);
				break;
			}
		}
	}

	return pstKv;
}

void GlbProKvReset(GLBPROKV_S* pstKv, USHORT usTotal, int iSize)
{
	USHORT usCount = 0;

	for (usCount = 0; usCount < usTotal; usCount ++) {
		if (NULL != (pstKv + usCount)->m_puszValue) {
			(pstKv + usCount)->m_ucKey = 0;
			(pstKv + usCount)->m_iLength = 0;
			memset((pstKv + usCount)->m_puszValue, '\0', iSize);
		}
	}

	return;
}

int GlbProKvInput(GLBPROKV_S* pstKv, USHORT usTotal, UCHAR* puszPacket, int iLength)
{
	USHORT usCount = 0;
	UCHAR* puszCur = puszPacket;

	while ((int)(puszCur - puszPacket) < iLength) {
		if (usCount < usTotal) {
			(pstKv + usCount)->m_ucKey = *puszCur;
			(pstKv + usCount)->m_iLength = ntohl(*(int*)(puszCur + sizeof(UCHAR)));
			(pstKv + usCount)->m_puszValue = puszCur + GLB_PRO_KEYLEN;
		}
		else {
			return GLB_FAILURE;
		}
		puszCur += GLB_PRO_KEYLEN + (pstKv + usCount)->m_iLength;
		usCount += 1;
	}

	return GLB_SUCCESS;
}

int GlbProKvOutput(GLBPROKV_S* pstKv, USHORT usTotal, UCHAR* puszPacket, int iLength)
{
	USHORT usCount = 0;
	UCHAR* puszCur = puszPacket;

	while ((int)(puszCur - puszPacket) < iLength) {
		if (usCount < usTotal) {
			if ('\0' != (pstKv + usCount)->m_ucKey) {
				*puszCur = (pstKv + usCount)->m_ucKey;
				*(int*)(puszCur + sizeof(UCHAR)) = htonl((pstKv + usCount)->m_iLength);
				memcpy(puszCur + GLB_PRO_KEYLEN, (pstKv + usCount)->m_puszValue, (pstKv + usCount)->m_iLength);
				puszCur += GLB_PRO_KEYLEN + (pstKv + usCount)->m_iLength;
			}
			else {
				break;
			}
		}
		else {
			break;
		}
		usCount += 1;
	}

	return (int)(puszCur - puszPacket);
}

void GlbProWkvFree(GLBPROWKV_S** ppstWkv, USHORT usTotal)
{
	USHORT usCount = 0;

	for (usCount = 0; usCount < usTotal; usCount ++) {
		if (NULL != (*ppstWkv + usCount)->m_puszValue) {
			GlbFree((void**)&(*ppstWkv + usCount)->m_puszValue);
		}
	}
	GlbFree((void**)ppstWkv);

	return;
}

void GlbProWkvDisplay(GLBPROWKV_S* pstWkv, USHORT usTotal)
{
	USHORT usCount = 0;
	char* pszValue = NULL;

	while (usCount < usTotal) {
		if ('\0' != (pstWkv + usCount)->m_usKey) {
			if (NULL != (pszValue = (char*)GlbMalloc(sizeof(char) * (pstWkv + usCount)->m_iLength + 1))) {
				memcpy(pszValue, (pstWkv + usCount)->m_puszValue, (pstWkv + usCount)->m_iLength);
				GLB_PRINT("Wkey[%05d] -> Len[%08d] -> Val[%s]\n", (pstWkv + usCount)->m_usKey, (pstWkv + usCount)->m_iLength, pszValue);
				GlbFree((void**)&pszValue);
			}
		}
		else {
			break;
		}
		usCount += 1;
	}

	return;
}

GLBPROWKV_S* GlbProWkvMalloc(USHORT usTotal, int iSize)
{
	USHORT usCount = 0;
	GLBPROWKV_S* pstWkv = NULL;

	if (NULL != (pstWkv = (GLBPROWKV_S*)GlbMalloc(sizeof(GLBPROWKV_S) * usTotal))) {
		for (usCount = 0; usCount < usTotal; usCount ++) {
			if (NULL == ((pstWkv + usCount)->m_puszValue = (UCHAR*)GlbMalloc(sizeof(UCHAR) * iSize))) {
				GLB_ERROR("%s\n", strerror(errno));
				GlbProWkvFree(&pstWkv, usTotal);
				break;
			}
		}
	}

	return pstWkv;
}

void GlbProWkvReset(GLBPROWKV_S* pstWkv, USHORT usTotal, int iSize)
{
	USHORT usCount = 0;

	for (usCount = 0; usCount < usTotal; usCount ++) {
		if (NULL != (pstWkv + usCount)->m_puszValue) {
			(pstWkv + usCount)->m_usKey = 0;
			(pstWkv + usCount)->m_iLength = 0;
			memset((pstWkv + usCount)->m_puszValue, '\0', iSize);
		}
	}

	return;
}

int GlbProWkvInput(GLBPROWKV_S* pstWkv, USHORT usTotal, UCHAR* puszPacket, int iLength)
{
	USHORT usCount = 0;
	UCHAR* puszCur = puszPacket;

	while ((int)(puszCur - puszPacket) < iLength) {
		if (usCount < usTotal) {
			(pstWkv + usCount)->m_usKey = ntohs(*(USHORT*)puszCur);
			(pstWkv + usCount)->m_iLength = ntohl(*(int*)(puszCur + sizeof(USHORT)));
			(pstWkv + usCount)->m_puszValue = puszCur + GLB_PRO_WKEYLEN;
		}
		else {
			return GLB_FAILURE;
		}
		puszCur += GLB_PRO_WKEYLEN + (pstWkv + usCount)->m_iLength;
		usCount += 1;
	}

	return GLB_SUCCESS;
}

int GlbProWkvOutput(GLBPROWKV_S* pstWkv, USHORT usTotal, UCHAR* puszPacket, int iLength)
{
	USHORT usCount = 0;
	UCHAR* puszCur = puszPacket;

	while ((int)(puszCur - puszPacket) < iLength) {
		if (usCount < usTotal) {
			if ('\0' != (pstWkv + usCount)->m_usKey) {
				*(USHORT*)puszCur = htons((pstWkv + usCount)->m_usKey);
				*(int*)(puszCur + sizeof(USHORT)) = htonl((pstWkv + usCount)->m_iLength);
				memcpy(puszCur + GLB_PRO_WKEYLEN, (pstWkv + usCount)->m_puszValue, (pstWkv + usCount)->m_iLength);
				puszCur += GLB_PRO_WKEYLEN + (pstWkv + usCount)->m_iLength;
			}
			else {
				break;
			}
		}
		else {
			break;
		}
		usCount += 1;
	}

	return (int)(puszCur - puszPacket);
}

void GlbProDisplay(GLBPROHDRS_S* pstHdrs)
{
	GLB_PRINT("Flag: 0x%02x\t", pstHdrs->m_ucFlag);
	GLB_PRINT("Vers: 0x%02x\t", *(UCHAR*)&pstHdrs->m_stOpts >> 4);
	GLB_PRINT("Prot: 0x%02x\t", ((*(UCHAR*)&pstHdrs->m_stOpts & 0x0f) >> 3));
	GLB_PRINT("Wide: 0x%02x\t", (*(UCHAR*)&pstHdrs->m_stOpts & 0x07) >> 2);
	GLB_PRINT("Resp: 0x%02x\t", (*(UCHAR*)&pstHdrs->m_stOpts & 0x03) >> 1);
	GLB_PRINT("Expa: 0x%02x\n", (*(UCHAR*)&pstHdrs->m_stOpts & 0x01));
	GLB_PRINT("Type: 0x%02x\t", pstHdrs->m_ucType);
	GLB_PRINT("Verb: 0x%02x\t", pstHdrs->m_ucVerb);
	GLB_PRINT("Attr: 0x%02x\t", pstHdrs->m_ucAttr);
	GLB_PRINT("Result: 0x%02x\t", pstHdrs->m_ucResult);
	GLB_PRINT("Total: %d\t", pstHdrs->m_usTotal);
	GLB_PRINT("Length: %d\n", pstHdrs->m_iLength);

	return;
}

void GlbProParse(GLBPROHDRS_S* pstHdrs, UCHAR* puszPacket, int iLength)
{
	UCHAR* puszCur = puszPacket;

	pstHdrs->m_ucFlag = *puszCur ++;
	memcpy(&pstHdrs->m_stOpts, puszCur ++, sizeof(UCHAR));
	pstHdrs->m_ucType = *puszCur ++;
	pstHdrs->m_ucVerb = *puszCur ++;
	pstHdrs->m_ucAttr = *puszCur ++;
	pstHdrs->m_ucResult = *puszCur ++;

	pstHdrs->m_usTotal = ntohs(*(USHORT*)puszCur);
	puszCur += sizeof(USHORT);

	pstHdrs->m_iLength = ntohl(*(int*)puszCur);
	puszCur += sizeof(int);

	return;
}

void GlbProCreate(GLBPROHDRS_S* pstHdrs, UCHAR* puszPacket, int iLength)
{
	UCHAR* puszCur = puszPacket;

	*puszCur ++ = pstHdrs->m_ucFlag;
	*puszCur ++ = *(UCHAR*)&pstHdrs->m_stOpts;
	*puszCur ++ = pstHdrs->m_ucType;
	*puszCur ++  = pstHdrs->m_ucVerb;
	*puszCur ++ = pstHdrs->m_ucAttr;
	*puszCur ++ = pstHdrs->m_ucResult;

	*(USHORT*)puszCur = htons(pstHdrs->m_usTotal);
	puszCur += sizeof(USHORT);

	*(int*)puszCur = htonl(pstHdrs->m_iLength);
	puszCur += sizeof(int);

	return;
}

} /* GlbNet */
